using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;

namespace TimeWar
{
    public class Octree : IOctree
    {
        protected internal OctreeNode top;

        public Octree()
            : this(1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 20, OctreeNode.NO_MIN_SIZE)
        {
        }

        public Octree(float xMax, float xMin, float yMax, float yMin, float zMax, float zMin, int maxItems)
            : this(xMax, xMin, yMax, yMin, zMax, zMin, maxItems, OctreeNode.NO_MIN_SIZE)
        {
        }

        public Octree(int up, int left, int down, int right, int Front, int Back, int maxItems)
            : this((float)up, (float)left, (float)down, (float)right, (float)Front, (float)Back, maxItems, OctreeNode.DEFAULT_MIN_SIZE)
        {
        }

        public Octree(float xMax, float xMin, float yMax, float yMin, float zMax, float zMin, int maxItems, float minSize)
        {
            top = new OctreeNode(xMax, xMin, yMax, yMin, zMax, zMin, maxItems, minSize);
        }

        #region Add Node

        /// <summary> Add a object into the tree at a location.
        /// </summary>
        /// <param name="x">up-down location in Octree Grid</param>
        /// <param name="y">left-right location in Octree Grid</param>
        /// <param name="z">front-back location in Octree Grid</param>
        /// <returns> true if the insertion worked. </returns>

        public bool AddNode(Vector3 vector, VectorShape obj)
        {
            return top.AddNode(vector, obj);
        }

#endregion Add Node


        #region Remove Node
        /// <summary> Remove a object out of the tree at a location. </summary>
        /// <param name="x">up-down location in Octree Grid (x, y)</param>
        /// <param name="y">left-right location in Octree Grid (y, x)</param>
        /// <returns> the object removed, null if the object not found.
        /// </returns>
        public VectorShape RemoveNode(Vector3 vector, VectorShape obj)
        {
            return top.RemoveNode(vector, obj);
        }
        #endregion

        #region Get Node

        /// <summary> Get an object closest to a x/y. </summary>
        /// <param name="x">up-down location in Octree Grid (x, y)</param>
        /// <param name="y">left-right location in Octree Grid (y, x)</param>
        /// <returns> the object that was found.</returns>
        public VectorShape GetNode(Vector3 vector)
        {
            return top.GetNode(vector);
        }

        /// <summary> Get an object closest to a x/y, within a maximum distance.
        /// 
        /// </summary>
        /// <param name="x">up-down location in Octree Grid (x, y)
        /// </param>
        /// <param name="y">left-right location in Octree Grid (y, x)
        /// </param>
        /// <param name="withinDistance">the maximum distance to get a hit, in
        /// decimal degrees.
        /// </param>
        /// <returns> the object that was found, null if nothing is within
        /// the maximum distance.
        /// </returns>
        public VectorShape GetNode(Vector3 vector, double withinDistance)
        {
            return top.GetNode(vector, withinDistance);
        }

        /// <summary> Get all the objects within a bounding box.
        /// 
        /// </summary>
        /// <param name="Top">top location in Octree Grid (x, y)
        /// </param>
        /// <param name="Left">left location in Octree Grid (y, x)
        /// </param>
        /// <param name="Bottom">lower location in Octree Grid (x, y)
        /// </param>
        /// <param name="Right">right location in Octree Grid (y, x)
        /// </param>
        /// <returns> ArrayList of objects.
        /// </returns>
        public List<VectorShape> GetNode(float xMax, float xMin, float yMax, float yMin, float zMax, float zMin)
        {
            return GetNode(xMax, xMin, yMax, yMin, zMax, zMin, new List<VectorShape>(100));
        }
        public List<VectorShape> GetNode(double xMax, double xMin, double yMax, double yMin, double zMax, double zMin)
        {
            return GetNode(xMax, xMin, yMax, yMin, zMax, zMin, new List<VectorShape>(10));
        }

        /// <summary> Get all the objects within a bounding box, and return the
        /// objects within a given Vector.
        /// 
        /// </summary>
        /// <param name="Top">top location in Octree Grid (x, y)
        /// </param>
        /// <param name="Left">left location in Octree Grid (y, x)
        /// </param>
        /// <param name="Bottom">lower location in Octree Grid (x, y)
        /// </param>
        /// <param name="Right">right location in Octree Grid (y, x)
        /// </param>
        /// <param name="vector">a vector to add objects to.
        /// </param>
        /// <returns> ArrayList of objects.
        /// </returns>
        public List<VectorShape> GetNode(float xMax, float xMin, float yMax, float yMin, float zMax, float zMin, List<VectorShape> nodes)
        {
            if (nodes == null)
                nodes = new List<VectorShape>();

            if (xMin > xMax || (Math.Abs(xMin - xMax) < 1e-6))
                return top.GetNode(xMax, xMin, yMax, yMin, zMax, zMin, top.GetNode(xMax, 0, yMax, yMin, zMax, zMin, nodes));
            else
                return top.GetNode(xMax, xMin, yMax, yMin, zMax, zMin, nodes);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="xMax"></param>
        /// <param name="xMin"></param>
        /// <param name="yMax"></param>
        /// <param name="yMin"></param>
        /// <param name="zMax"></param>
        /// <param name="zMin"></param>
        /// <param name="nodes"></param>
        /// <returns></returns>
        public List<VectorShape> GetNode(double xMax, double xMin, double yMax, double yMin, double zMax, double zMin, List<VectorShape> nodes)
        {
            if (nodes == null)
                nodes = new List<VectorShape>();

            if (xMin > xMax || (Math.Abs(xMin - xMax) < 1e-6))
                return top.GetNode(xMax, xMin, yMax, yMin, zMax, zMin, top.GetNode(xMax, 0, yMax, yMin, zMax, zMin, nodes));
            else
                return top.GetNode(xMax, xMin, yMax, yMin, zMax, zMin, nodes);
        }

        #endregion

        #region Get Nodes
        /// <summary> Get an object closest to a x/y, within a maximum distance.
        /// 
        /// </summary>
        /// <param name="x">up-down location in Octree Grid (x, y)
        /// </param>
        /// <param name="y">left-right location in Octree Grid (y, x)
        /// </param>
        /// <param name="withinDistance">the maximum distance to get a hit, in
        /// decimal degrees.
        /// </param>
        /// <returns> the objects that were found  within the maximum radius.
        /// </returns>
        public List<VectorShape> GetNodes(Vector3 vector, double radius)
        {
            return top.GetNodes(vector, radius);
        }

        /// <summary> Get an object closest to a x/y, within a maximum distance./// </summary>
        /// <param name="x">up-down location in Octree Grid (x, y)</param>
        /// <param name="y">left-right location in Octree Grid (y, x)</param>
        /// <param name="withinDistance">the maximum distance to get a hit, in
        /// decimal degrees.</param>
        /// <returns> the objects that were found  within the maximum radius.</returns>
        public List<VectorShape> GetNodes(Vector3 vector, double MinRadius, double MaxRadius)
        {
            return top.GetNodes(vector, MinRadius, MaxRadius);
        }
        #endregion

        /// <summary>Clear the tree. </summary>
        public void Clear()
        {
            top.Clear();
        }

    }
}